/*
 * @文件描述: 
 * @版本: 
 * @作者: 周晨阳
 * @Date: 2021-01-13 23:32:23
 */
#include "ResistanceMeter.h"
#include "myADC.h"
/* Private typedef -----------------------------------------------------------*/

/* Private define ------------------------------------------------------------*/
//分压电阻，单位k
#define R19 1000.0f

//控制引脚 使用PB3
#define RESISTANCE_GPIO_PIN GPIO_Pin_7
#define RESISTANCE_GPIO_PORT GPIOC
#define RESISTANCE_GPIO_CLK RCC_APB2Periph_GPIOC

/* Private macro -------------------------------------------------------------*/
#define AVR_NUM 1000
#define X10_GATE 5
#define X1_GATE 7

/* Private variables ---------------------------------------------------------*/
//私有变量
static unsigned char state = 0;
static float raw_value = 0;
static float Res = 0;
static float AdjRes = 0;
static unsigned char unit = UNIT_KOHM;
//放大器的放大倍数
static int ampFactor = 1;
static uint8_t dataReady = 0;
static int dataPointer = 0;
static float lastRes = 0;

static float inputData[AVR_NUM];
static float outputData[20];

/* Private function prototypes -----------------------------------------------*/

/* Private functions ---------------------------------------------------------*/

/**
 * @description: //adc数值更新的回调函数
 * @param {type}
 * @return {type}
 */
static void AdcInterrupt(int value)
{
  //更新数值
  //MultiMeter_ADC_Stop();
  raw_value = value;

  if (dataPointer < AVR_NUM)
  {
    dataReady = 0;
    inputData[dataPointer] = (float)value;
    dataPointer++;
    //MultiMeter_ADC_Start();
  }
  else
  {
    MultiMeter_ADC_Stop();
    dataReady = 1;
  }

#ifdef ADC_RAW_VALUE
  printf("resistanceMeter ADC raw :%d \n", value);
#endif
}
/**
 * @description: 欧姆表adc初始化（内部函数）
 * @param {type}
 * @return {type}
 */
static void ResistanceMeter_ADC_Init()
{
#ifndef WIN_SIM
    MultiMeter_ADCx_Init_auto(ADC2, RESISTANCE_ADC_CHANNEL);

#endif // !WIN_SIM

  ampFactor = 1;
}
/**
 * @description: 打开欧姆表
 * @param {type}
 * @return {type}
 */
void openResistanceMeter()
{
  ResistanceMeter_ADC_Init();
  setCallbackFunc(AdcInterrupt);
  //  GPIO_SetBits(RESISTANCE_GPIO_PORT, RESISTANCE_GPIO_PIN);
  MultiMeter_ADC_Start();
  state = 1;

#ifdef DEBUG_MODE
  printf("ResistanceMeter is opened\n");
#endif
}
/**
 * @description: 关闭欧姆表
 * @param {type}
 * @return {type}
 */
void closeResistanceMeter()
{

  MultiMeter_ADC_Stop();
  setCallbackFunc(NULL);
  // GPIO_ResetBits(RESISTANCE_GPIO_PORT, RESISTANCE_GPIO_PIN);

  state = 0;

#ifdef DEBUG_MODE
  printf("ResistanceMeter is closed\n");
#endif
}
/**
 * @description: 获取欧姆表当前状态
 * @param {type}
 * @return {type}
 */
unsigned char getResistanceMeterState() { return state; }

/**
 * @description: 欧姆表初始化
 * @param {type}
 * @return {type}
 */
void ResistanceMeterInit()
{

  ResistanceADC_GPIO_Init();
#ifdef NO_BOARD
  printf("ResistanceMeter is OFF due to NO_BOARD mode\n");

#endif
  printf("ResistanceMeter Init   done...\n");
}
/**
 * @brief : 获取原始电阻值，单位欧姆
 * @param {*}
 * @return {*}
 */
float getRawRes()
{
  return Res;
}
/**
 * @description: 获取电阻值，该函数获取的阻值单位不定，
 * 需要配合getR_Unit()一起使用(为的是UI可以直接显示数值而不用对数值再做处理)
 * @param {type}
 * @return {float 电阻值}
 */
float getCurrentRes()
{
  return AdjRes;
}
/**
 * @description: 获取欧姆表当前数值的单位
 * @param {type}
 * @return {单位}}
 */
unsigned char getR_Unit()
{
  //如果小于1k，单位为R
  if (Res < 1000.0f)
  {
    return UNIT_OHM;
  }
  //如果大于1k小于1M，单位为KR
  else if (Res > 1000.0f && Res < 1000000.0f)
  {
    return UNIT_KOHM;
  }
  //如果大于1M，单位为MR
  else if (Res > 1000000.0f)
  {
    return UNIT_MOHM;
  }
  else
  {
    return UNIT_OHM;
  }
}
/**
 * @description: 更改欧姆表的量程
 * @param {int} factor
 * @return {*}
 */
void changeResistanceFactor(int factor) { ampFactor = factor; }
/**
 * @description: 获取欧姆表当前的量程，1或10
 * @param {*}
 * @return {int： 量程}
 */
int getResistanceFactor() { return ampFactor; }
/**
 * @brief : 获取欧姆表指针角度
 * @param {*}
 * @return {*}
 */
float getResNeedleAngle()
{
  float angle;
  if (ampFactor == 1)
  {
    angle = -36.5f + Res * (73.0f / 2000000.0f);
  }
  else
  {
    angle = -36.5f + Res * (73.0f / 40000.0f);
  }
  if (angle > 36.5f)
  {
    angle = 36.5f;
  }
  if (angle < -36.5f)
  {
    angle = -36.5f;
  }

  return angle;
}

/**
 * @description: 数值更新函数，请尽量不要在其中进行耗时操作
 * @param {type}
 * @return {type}
 */
void ResistanceMeterLooper()
{

  int l;
  float adjValue;
  // adc自测电压
  float adcVoltage;
  //被测电阻两端的电压
  float RxVoltage;
  //计算后的阻值，单位为k
  double res;

  if (!state && dataReady == 0)
  {
    return;
  }
  dataReady = 0;
  adjValue = 0;

#ifndef SIMULATE_VALUE

#ifdef USE_FIR
  //firFilterFloat(inputData, outputData, 20);
  dataPointer = 0;

  //算术平均
  for (l = 0; l < AVR_NUM; l++)
  {
    res += inputData[l];
  }
  res /= (float)AVR_NUM;

//加入限幅滤波算法，防止数字不停抖动
#ifdef ANTI_INTERFERENCE

  if (ampFactor == 1)
  {
    if (fabs(res - lastRes) < X1_GATE)
    {
      res = lastRes;
    }
    else
    {
      lastRes = res;
    }
  }
  else if (ampFactor == 10)
  {
    if (fabs(res - lastRes) < X10_GATE)
    {
      res = lastRes;
    }
    else
    {
      lastRes = res;
    }
  }
#else
  lastRes = res;
#endif

  // adc自测电压
  adcVoltage = (res / 4096.0f) * 3.3f;
  //被测电阻两端的电压
  RxVoltage = (adcVoltage / (1.5f * ampFactor));
  //计算后的阻值，单位为k
  res = (R19 * RxVoltage) / (VCC - RxVoltage);

#endif

#ifdef DEBUG_MODE
  printf("raw Res is :%f kR \n", res);
#endif

/************校准数据*******************/
#ifdef USE_CALIBRATION

  //此处添加多项式拟合调整误差的操作,y=ax3+bx2+cx+d,其中，y为真实值，x为该系统测出来的值
  // x10 时的拟合公式y = 1.0617x - 0.4735

#define X3 (1.0617f)
#define X2 (-0.4735f)

  // x1时的拟合公式y = 3.89750E-06x3 + 1.50741E-04x2 + 1.14046E+00x - 2.75699E+00R² = 9.99965E-01

#define _A (3.89750E-06f)
#define _B (1.50741E-04f)
#define _C (1.14046E+00f)
#define _D (-2.75699E+00f)
  if (ampFactor == 10)
  {
    res = X3 * res + X2;
  }
  else if (ampFactor == 1)
  {
    res = _A * pow(res, 3) + _B * pow(res, 2) + _C * res + _D;
  }
#endif

  /************校准结束*******************/
  //为全局变量赋值，全局变量res的单位为欧姆
  Res = res * 1000.0f;

/******自动根据数值大小放大数值***********/
#ifdef USE_AUTO_VALUE
  //值小于1k
  if (res < 1.0f)
  {
    adjValue = res * 1000.0f;
  }
  //值大于1k小于1M
  else if (res > 1.0f && res < 1000.0f)
  {
    adjValue = res;
  }
  //值大于1M
  else if (res > 1000.0f)
  {
    adjValue = res / 1000.0f;
  }
#else
  adjValue = res;
#endif

  AdjRes = adjValue;
  MultiMeter_ADC_Start();

#else
  AdjRes = 1200;
  Res = 1200;
#endif
}
